#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         CheckBox.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Tom Cameron, Brian Oliver
#
# Description:  A CheckBox is a primitive Component
#               to represent simple true/false/undefined information
#               in an assessment.
#
#               Originally this component was based on the
#               BooleanComponent in pre 1.0 versions of the
#               KnowledgeEngine. However as this component now
#               supports the additional 'undefined' state, it is
#               no longer a strickly 'boolean' component.
#
# See Also:     Component, Model, Section
#####################################################################

#####################################################################
## Knowledge Engine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Component import Component, ComponentInfo
from Products.KnowledgeEngine.Assessible import Assessible
from Products.KnowledgeEngine.AssessmentFilter import AssessmentFilter
from Products.KnowledgeEngine.AssessmentComponentState import AssessmentComponentState
from Products.KnowledgeEngine.AssessmentComponentValueTypes import *
from Products.KnowledgeEngine.Exportable import Exportable
from Products.KnowledgeEngine.KERLExtensions import KERLExtensions
from Products.KnowledgeEngine.KERLProcessor import *
from Products.KnowledgeEngine.KERFProcessor import *
from Products.KnowledgeEngine.Scorable import *
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *
from Products.KnowledgeEngine.Graphing.Graphable import *
from Products.KnowledgeEngine.Graphing.Datum import *
from Products.KnowledgeEngine.User import User
from Products.KnowledgeEngine.Caching import RequestCache
from Products.KnowledgeEngine.KERLProcessor import InvalidKerlOperator

#####################################################################
## Zope Library Imports
from Globals import DTMLFile
from App.ImageFile import ImageFile

#####################################################################
## Zope CMF Library Imports
from Products.CMFCore.PortalContent import PortalContent
from Products.CMFCore.ActionInformation import ActionInformation
from Products.CMFCore import permissions
from Products.CMFCore.permissions import ModifyPortalContent

#####################################################################
## Python Library Imports
import types

#####################################################################
## CheckBoxInfo Class Definition
class CheckBoxInfo(ComponentInfo, ScorableInfo):
    """
        Defines the class info methods, defining information about
        the class without needing an instance of the class
    """

    #---------------------------------------------------------------#

    def getClassName(self):
        """
            Return the class name
        """

        return 'CheckBox'

    #---------------------------------------------------------------#

    def getDisplayName(self):
        """
            Return a friendly name for the class instances
            (this is used for displaying in lists etc)
        """

        return "Choice Question"

    #---------------------------------------------------------------#

    def getIdentityType(self):
        """
            Return the identity type.
        """

        return "chk"

    #---------------------------------------------------------------#

    def getClassIcon(self):
        """
            Return the appropriate icon file for the class.
        """

        return ImageFile('skins/CheckBox_icon.gif', globals())

    #---------------------------------------------------------------#

    def isInstanceOf(self, className):
        """
            Returns if the class is an instance of the specified
            className, or implements the interface specified
            by the className
        """

        return className in ('Assessible', 'Exportable') or ScorableInfo.isInstanceOf(self,className) or ComponentInfo.isInstanceOf(self, className)

    #---------------------------------------------------------------#

    def onConfigureProperties(self):
        """
            Automatically called by the Knowledge Engine once
            the class has been loaded.  Use this method to register
            class specific properties using the PropertyReflection interface.

            If this class is sub-classed, a call must be made to
            the super-class to ensure super-class properties are
            correctly registered

            NOTE: This method is called before ClassInfo.onAfterStartup()
        """

        #initialise the super-class properties for reflection
        ComponentInfo.onConfigureProperties(self)
        ScorableInfo.onConfigureProperties(self)

        #add the 'reportContentWhenSelected' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenSelected", displayName="Report Content (when Yes is selected)", description="Text to be displayed in a report for this component when it is true/on/yes.", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'reportContentWhenUnselected' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenUnselected", displayName="Report Content (when No is selected)", description="Text to be displayed in a report for this component when it is false/off/no.", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'reportContentWhenUndefined' property
        self.addPropertyDefinition(PropertyDefinition(identity="reportContentWhenUndefined", displayName="Report Content (when Nothing is selected)", description="Text to be displayed in a report for this component when no selection has been made", defaultValue="", propertyType=pt_STRING, propertyFormat=pf_HTML, propertyStructure=ps_ATOMIC))

        #add the 'defaultValue' property
        self.addPropertyDefinition(PropertyDefinition(identity="defaultValue", displayName="Default Value", description="The value used for this component i). in newly created assessments, ii). when added to a model and assessments already exist in that model, or iii). when not changed by a user in an assessment", propertyType=pt_INTEGER, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesMapping=[("Yes", true),("No", false),("(undefined)",undefined)], defaultValue=undefined))

        #add the 'displayFormat' property
        self.addPropertyDefinition(PropertyDefinition(identity="displayFormat", displayName="Display As", description="What values should be displayed?", propertyType=pt_STRING, propertyFormat=pf_NATIVE, hasEnumeratedValues=true, enumeratedValuesList=["Yes/No","True/False","On/Off"], defaultValue="Yes/No"))

        #add the 'scoreTrue' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreTrue", displayName="Score (when Yes is selected)", description="The score for the component when Selected/On/Yes/Checked in an assessment", defaultValue=1.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

        #add the 'scoreFalse' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreFalse", displayName="Score (when No is selected)", description="The score for the component when Unelected/Off/No/Unchecked in an assessment", defaultValue=0.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

        #add the 'scoreFalse' property
        self.addPropertyDefinition(PropertyDefinition(identity="scoreUndefined", displayName="Score (when Nothing is selected)", description="The score for the component when no selection has been made in an assessment", defaultValue=0.0, propertyType=pt_FLOAT, propertyFormat=pf_NATIVE, propertyStructure=ps_ATOMIC))

    #---------------------------------------------------------------#

#####################################################################
## CheckBox Class Definition
class CheckBox(Component, Assessible, KERLExtensions, Scorable, Exportable):
    """
        Defines a a simple component to represent a boolean selection
        in an assessment
    """

    #---------------------------------------------------------------#

    #TRANSIENT: a ClassInfo implementation instance to provide info about this class
    _CLASSINFO = CheckBoxInfo()

    #---------------------------------------------------------------#

    # Default Values for backward compatibility
    displayList = ["Yes/No","True/False","On/Off"]
    displayFormat = "Yes/No"
    scoreTrue = 1.0
    scoreFalse = 0.0
    scoreUndefined = 0.0

    #---------------------------------------------------------------#

    # DTML Methods
    index_html = DTMLFile('dtml/index_html', globals())
    simplereport_html = DTMLFile('dtml/simplereport_html', globals())
    scoredreport_html = DTMLFile('dtml/scoredreport_html', globals())
    scored360report_html = DTMLFile('dtml/scored360report_html', globals())
    csv360report_html = DTMLFile('dtml/csv360report_html', globals())
    groupedreport_html = DTMLFile('dtml/groupedreport_html', globals())

    #---------------------------------------------------------------#

    def __init__(self, id, identity):
        "Constructor for the CheckBox"

        Component.__init__(self, id, identity)

    #---------------------------------------------------------------#

    def onAfterInstanciation(self):
        """
            Handle Knowledge Engine specific actions after this object
            has been loaded into memory.

            This is useful for performing backwards compatibility
        """

        #perform Component.onAfterInstanciation processing
        Component.onAfterInstanciation(self)

        #as we no longer support the 'checkbox' type of display, we need to convert it to a Yes/No type
        if self.getDisplayFormat() == 'CheckBox':
            self.setDisplayFormat("Yes/No")

        ###print "DEBUG: CheckBox.onAfterInstanciation: Completed"

    #---------------------------------------------------------------#

    def getDisplayFormat(self):
        """
            Return the display format of this object
        """

        return self.displayFormat

    #---------------------------------------------------------------#

    def setDisplayFormat(self, displayFormat):
        """
            Set the display format of this object
        """

        self.displayFormat = displayFormat

    #---------------------------------------------------------------#

    def onAfterIdentityChange(self, identityMappings):
        """
            Handle Knowledge Engine specific actions after the
            identity of this object has changed.

            The identityMappings dictionary holds
            mappings from oldIdentities -> newIdentities
            (including this object)

        """

        #perform default identity changes
        Component.onAfterIdentityChange(self, identityMappings)

        #resolve report KERFs
        self.setReportContentWhenSelected(updateKERF(self.getReportContentWhenSelected(), identityMappings))
        self.setReportContentWhenUnselected(updateKERF(self.getReportContentWhenUnselected(), identityMappings))
        self.setReportContentWhenUndefined(updateKERF(self.getReportContentWhenUndefined(), identityMappings))

    #---------------------------------------------------------------#

    def getReportContentForValue(self, value):
        """ Returns the report content for the specified value on this component """

        if value == 1:
            return self.getReportContentWhenSelected()
        elif value == 0:
            return self.getReportContentWhenUnselected()
        else:
            return self.getReportContentWhenUndefined()

    #---------------------------------------------------------------#

    def getReportContentWhenSelected(self):
        """
            Returns the Report Content for this component
            when Yes is selected in an assessment
        """

        return self.reportContentWhenSelected

    #---------------------------------------------------------------#

    def setReportContentWhenSelected(self, reportContentWhenSelected):
        """
            Sets the Report Content for this component
            when Yes is selected in an assessment
        """

        self.reportContentWhenSelected = reportContentWhenSelected

    #---------------------------------------------------------------#

    def getReportContentWhenUnselected(self):
        """
            Returns the Report Content for this component
            when No is selected in an assessment
        """

        return self.reportContentWhenUnselected

    #---------------------------------------------------------------#

    def setReportContentWhenUnselected(self, reportContentWhenUnselected):
        """
            Sets the Report Content for this component
            when No is selected in an assessment
        """

        self.reportContentWhenUnselected = reportContentWhenUnselected

    #---------------------------------------------------------------#

    def getReportContentWhenUndefined(self):
        """
            Returns the Report Content for this component
            when nothing is selected in an assessment
        """

        return self.reportContentWhenUndefined

    #---------------------------------------------------------------#

    def setReportContentWhenUndefined(self, reportContentWhenUndefined):
        """
            Sets the Report Content for this component
            when nothing is selected in an assessment
        """

        self.reportContentWhenUndefined = reportContentWhenUndefined

    #---------------------------------------------------------------#

    def getDefaultValue(self):
        """
            Returns the default value of the component
            for new assessments; true = 1, false = 0 or undefined = -1
        """

        return self.defaultValue

    #---------------------------------------------------------------#

    def setDefaultValue(self, defaultValue):
        """
            Sets the default value of the component
            for new assessments; true = 1, false = 0 or undefined = -1
        """

        self.defaultValue = defaultValue

    #---------------------------------------------------------------#

    def getTypedAssessmentValue(self, formValue):
        """
            Returns the correctly typed python value for the
            specified HTTP form value

            Called By: AssesssmentCache.setState
        """

        #ensure the assessment value is a tristate
        if type(formValue) is types.StringType:
            if formValue == 'on' or formValue == 'checked' or formValue == 'selected' or formValue == 'true':
                return true
            elif formValue == 'off' or formValue == 'unchecked' or formValue == 'unselected' or formValue == 'false':
                return false
            else:
                return undefined

        else:
            return formValue

    #---------------------------------------------------------------#

    def getComponentProperty(self, identity, propertyName, assessment = None):
        """
            Returns the value of the specified property, given the
            identity of the component (which may be used to lookup states) and
            an assessment.

            RETURNS: None if the property doesnt exist
        """

        value = assessment.getComponentState(identity).getValue()

        if propertyName == "value":
            if value == true:
                return "Yes"
            elif value == false:
                return "No"
            else:
                return "Undefined"
        else:
            return Component.getComponentProperty(self, identity, propertyName, assessment)

    #---------------------------------------------------------------#

    def getScore(self, assessment):
        """
            Evaluates the unweighted score of the component..

            Typically called by Scorable.getScore() to retrieve
            score. Or Scorable.getScore()*Scorable.getWeighting()

            NOTE: Must return a real number
        """

        #get the identity
        identity = self.getIdentity()

        #get the stored state
        state = assessment.getComponentState(identity).getValue()

        #evaluate and return the score
        if state == true:
            return self.scoreTrue
        elif state == false:
            return self.scoreFalse
        else:
            return self.scoreUndefined

    #---------------------------------------------------------------#

    def getMaxScore(self):
        """
            Evaluates the maximum potential score
        """

        #evaluate and return the score
        return max([self.scoreTrue, self.scoreFalse, self.scoreUndefined])

    #---------------------------------------------------------------#
    # BEGIN: Assessible Implementation                              #
    #---------------------------------------------------------------#

    def getAssessmentValueType(self):
        """
            ABSTRACT: Returns the type of the value that is to be stored
            for this component when it's assessment state is persisted.

            NOTE 1: See AssessmentComponentValueTypes for a list of defined contants
            NOTE 2: This method MUST be overriden in the implementing
            class to specify the correct type for value persistence

            RETURN TYPE: String
        """

        #checkbox assessment values are tristates stored as booleans (booleans are actually numbers)
        return st_BOOLEAN

    #---------------------------------------------------------------#

    def getDefaultAssessmentState(self, assessment):
        """
            ABSTRACT: Constructs and returns a suitable 'default'
            AssessmentComponentState for the provided Assessment
            instance.

            NOTE: This method MUST be overriden in the implementing
            class to provide a suitable default value for the component

            RETURN TYPE: AssessmentComponentState
        """

        return AssessmentComponentState(assessment.getIdentity(), assessment.getModelIdentity(), self.getIdentity(), self.getAssessmentValueType(), self.getDefaultValue(), revision=assessment.getRevision())

    #---------------------------------------------------------------#

    def updateAssessmentState(self, assessment, formValue):
        """
            ABSTRACT: Updates the specified assessment using
            the provided HTTP REQUEST formValue.

            NOTE: This method MUST be overriden in the implementing
            class to suitably update the component state
        """
        
        Component.updateAssessmentState( self, assessment, formValue )
        
        if self.getIsMandatory() and formValue == 'undefined':
            raise FieldRequiredException( "Field Required", component=self )

        #ensure the assessment value is a correctly typed tristate
        if type(formValue) is types.StringType:
            if formValue == 'on' or formValue == 'checked' or formValue == 'selected' or formValue == 'true':
                value = true
                searchValue = true
            elif formValue == 'off' or formValue == 'unchecked' or formValue == 'unselected' or formValue == 'false':
                value = false
                searchValue = false
            else:
                value = undefined
                searchValue = ""
        else:
            searchValue = value = formValue
            

        #get the current assessment state for the component from the assessment
        state = assessment.getComponentState(self.getIdentity())

        #print "SETTING CHECKBOX %s = %s" % ( self.getIdentity(), `value` )

        #update the current state
        state.setValue(value)
        
        # If a searchIndex is defined, add that info to the component state
        searchIndex = getattr(self, 'searchIndex', False)
        if searchIndex:
            state.setSearchIndex(searchIndex)
            state.setSearchValue(searchValue)
            #if value == true:
                #state.setSearchIndex(searchIndex)
                #state.setSearchValue(value)
            #else:
                #state.setSearchIndex(searchIndex)
                #state.setSearchValue(va)            
        

        #update the assessment
        assessment.setIsModified(true)

    #---------------------------------------------------------------#
    # END: Assessible Implementation                                #
    #---------------------------------------------------------------#

    #---------------------------------------------------------------#
    # BEGIN: KERLExtensions Implementation                          #
    #---------------------------------------------------------------#

    def compileKERLtoJavaScript(self, expression):
        """
            Returns a Python string that represents a JavaScript
            expression, which may be used to evaluate the status
            of the component class specific KERL expression.

            NOTE: this method is primarily used to produce
            JavaScript expressions that form the basis of the
            client-side showif technology.

            RETURN TYPE: String
        """

        #example: cond="['bool1','selected']" returns 'document.getElementById("bool1").value=="true"'
        #example: cond="['bool1','unselected']" returns 'document.getElementById("bool1").value=="false"'
        #example: cond="['bool1','undefined']" returns 'document.getElementById("bool1").value!="true" && document.getElementById("bool1").value!="false"'

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]

        if value == "selected":
            return "document.getElementById(\"" + identity + "\").value==\"true\""
        elif value == "unselected":
            return "document.getElementById(\"" + identity + "\").value==\"false\""
        elif value == "undefined":        
            return "(document.getElementById(\"" + identity + "\").value!=\"true\" && document.getElementById(\"" + identity + "\").value!=\"false\")"
        else:
            return Component.compileKERLtoJavaScript( self, expression )
            
            
            
            #raise InvalidKerlOperator( value )
            #return "(document.getElementById(\"" + identity + "\").value!=\"true\" && document.getElementById(\"" + identity + "\").value!=\"false\")"

    #---------------------------------------------------------------#

    def compileKERLtoEnglish(self, expression):
        """
            Returns a string representing an 'English' version
            of the component class specific KERL expression.

            NOTE: this method is primarily used to produce
            English descriptions of KERL expressions that may be 
            used to describe things like AssessmentFilters
            
            RETURN TYPE: String         
        """

        #example: cond="['bool1','selected']" returns '<title> is <display:true>'
        #example: cond="['bool1','unselected']" returns '<title> is <display:false>'
        #example: cond="['bool1','undefined']" returns '<title> is undefined'

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]
        trueTitle = self.getDisplayFormat().split('/')[0];
        falseTitle = self.getDisplayFormat().split('/')[1];

        if value == "selected":
            return "%s '%s' is %s" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), trueTitle)
        elif value == "unselected":
            return "%s '%s' is %s" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), falseTitle)
        elif value == "undefined":
            return "%s '%s' is undefined" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), )
        elif value == "notattempted":        
            return "%s '%s' is not attempted" % (self.getClassInfo().getDisplayName(), self.getTitleOrId(), )
        else:
            raise InvalidKerlOperator( value )
            

    #---------------------------------------------------------------#

    def evaluate(self, expression, assessment):
        """
            Evalutes the component class specific KERL expression
            using the provided assessment.

            NOTE: this method is primarily used to produce
            JavaScript expressions that form the basis of the
            client-side showif technology.

            RETURN TYPE: Boolean
        """

        #get the identity
        identity = self.getIdentity()

        #get the value
        value = expression[1]

        #get the stored state (and ensure it is a boolean)
        state = assessment.getComponentState(identity)

        #evaluate the expression
        if value == "selected":
            return state.getValue() == true
        elif value == "unselected":
            return state.getValue() == false
        elif value == "undefined":
            return state.getValue() == undefined
        else:
            raise InvalidKerlOperator( value )
            

    #---------------------------------------------------------------#

    def getDependencies(self, expression):
        """
            Returns a list of components that are required to
            evaluate the component class specific KERL expression.

            NOTE: Includes the specific component itself.

            RETURN TYPE: {Component} indexed by Component.getIdentity()
       """

        return {self.getIdentity():self}

    #---------------------------------------------------------------#

    def updateKERLIdentities(self, expression, identityMappings):
        """
            Returns the expression with the appropriate old identities
            (as identified by the identityMappings) replaced with
            new identities.
        """

        #get the component identity from the expression (first element)
        identity = expression[0]

        #is the component in the identityMappings?
        if identityMappings.has_key(identity):
            expression[0] = identityMappings[identity]

        return expression

    #---------------------------------------------------------------#
    # END: KERLExtensions Implementation                            #
    #---------------------------------------------------------------#

    def generateGraphableStatistics(self, baseAssessmentFilter = None, user = None, nrAssessments = None):
        """
            Generates a Graphable instance containing statistic
            information for this component - that may be graphed.
            
            The provided assessmentFilter is used as a basis for
            generating statistics information.  Setting this to
            None (the default) means all assessments are used.
            
            RETURN TYPE: Graphable
        """
       
        #ensure the baseAssessmentFilter is valid (not None)
        if baseAssessmentFilter is None:
            baseAssessmentFilter = self.getModel().getAllAssessmentsFilter()
        
        #determine the true and false titles
        trueTitle = self.getDisplayFormat().split('/')[0]
        falseTitle = self.getDisplayFormat().split('/')[1]
        
        #we need to use the assessment storage service to get the statistics
        assessmentStorageService = self.getModel().getAssessmentStorageService()

        #determine the number of assessments (if necessary)
        if nrAssessments is None:
            nrAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(baseAssessmentFilter, user)   
        
        #we need a Graphable for the results
        graphable = Graphable(self.getTitleOrId(), "The following chart outlines the selection statistics for the '%s' component in the %d current assessments." % (self.getTitleOrId(), nrAssessments), 0, nrAssessments)
        
        #create a datum for the number of times the component has been selected in the assessments
        filterTitle = "%s selections for %s" % (trueTitle, self.getTitleOrId())
        filterExpression = parseKERL("['%s', 'selected']" % self.getIdentity())
        assessmentFilter = AssessmentFilter(title=filterTitle, expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), filterExpression]), model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())
        
        nrSelectedAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(assessmentFilter, user)
        datum = Datum(identity="selected", title="# %s." % trueTitle, value=nrSelectedAssessments, color="green", context={"ASSESSMENT_FILTER":assessmentFilter})
        graphable.addDatum(datum)

        #create a datum for the number of times the component has been unselected in the assessments
        filterTitle = "%s selections for %s" % (falseTitle, self.getTitleOrId())
        filterExpression = parseKERL("['%s', 'unselected']" % self.getIdentity())
        assessmentFilter = AssessmentFilter(title=filterTitle, expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), filterExpression]), model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())
        
        nrUnselectedAssessments = assessmentStorageService.getNrAssessmentsSatisfyingFilter(assessmentFilter, user)
        datum = Datum(identity="unselected", title="# %s." % falseTitle, value=nrUnselectedAssessments, color="red", context={"ASSESSMENT_FILTER":assessmentFilter})
        graphable.addDatum(datum)

        undefinedKerl = [self.getIdentity(), 'notattempted']

        undefinedFilter = AssessmentFilter(title="Undefined Assessments", expression=simplifyKERL(['all', baseAssessmentFilter.getExpression(), undefinedKerl]), 
                                           model=self.getModel(), assessmentScope=baseAssessmentFilter.getAssessmentScope())

        #create a datum for the number of times the component has been unselected in the assessments
        datum = Datum(identity="undefined", title="# Undefined.", value=nrAssessments - nrSelectedAssessments - nrUnselectedAssessments, color="orange", 
                      context = {'ASSESSMENT_FILTER': undefinedFilter},
                      footnote="As it is possible for an end-user to avoid selecting either '%s' or '%s' for Choices, some assessments may have 'undefined' values." % (trueTitle, falseTitle))
                      
        graphable.addDatum(datum)
        
        return graphable

    #---------------------------------------------------------------#

    def listActions(self, info=None):
        """
            PLONE Support:

            Returns a tuple of ActionInformation instances
            specifying the available CMF Actions for the object

            overrides:

            (CMF Actions are different from Knowledge Engine Actions)
        """

        #add the super-class actions first
        lCMFActions = Component.listActions(self, info)

        #add the 'statistics' action
        lCMFActions = lCMFActions + (
                        ActionInformation(
                            id='statistics',
                            title='statistics',
                            description='Current Statistics',
                            category='object',
                            condition='',
                            permissions=(permissions.ListFolderContents,),
                            priority=1,
                            visible=1,
                            action='string:${object_url}/CheckBox_Statistics'
                        ),)
                        
        return lCMFActions

    #---------------------------------------------------------------#
    
    def hasReportContent( self ):
        """ Does this component have report content? """
        
        return ( Component.hasReportContent( self ) or 
                 self.getReportContentWhenSelected() or 
                 self.getReportContentWhenUndefined() or
                 self.getReportContentWhenUnselected() )
    
    
    
#####################################################################
## Class Initialisation

# Register Class Information with the Knowledge Engine
registerGenericObjectClass(CheckBox)

#####################################################################
